package fun.qu_an.minecraft.fabric.fzbbl.event;

import fun.qu_an.minecraft.fabric.fzbbl.api.IPistonCache;
import fun.qu_an.minecraft.fabric.fzbbl.util.BlockUtils;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FacingBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.Items;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;

public class ServerPistonCarvingEventsRouter implements ModInitializer {
	private static final Logger LOGGER = LogManager.getLogger(ServerPistonCarvingEventsRouter.class);

	@Override
	public void onInitialize() {
		PlayerPlaceEvents.PLACING.register(this::onPlayerPlacing);
		PistonEvents.CONTRACTING.register(this::contracting);
		ServerTickEvents.END_WORLD_TICK.register(world -> ((IPistonCache) world).clearPistonCache());
	}

	private boolean onPlayerPlacing(@NotNull ItemPlacementContext context) {
		World world = context.getWorld();
		if (world.isClient
			// 判断玩家放的是不是活塞
			|| context.getStack().getItem() != Items.PISTON) {
			return true;
		}
		BlockPos pistonPos = context.getBlockPos();
		Direction pistonFacing = context.getPlayerLookDirection().getOpposite();
		BlockPos unbreakablePos = pistonPos.offset(pistonFacing);
		Block offsetBlock = world.getBlockState(unbreakablePos).getBlock();
		if (BlockUtils.isUnbreakable(offsetBlock)) {
			LOGGER.debug("placed piston point to unbreakable!");
			// 活塞缓存
			((IPistonCache)world).putPistonCache(pistonPos, (ServerPlayerEntity) context.getPlayer());
		}
		return true;
	}

	private boolean contracting(@NotNull World world, BlockPos pistonPos, BlockState pistonState) {
		if (world.isClient) {
			return true;
		}
		Direction pistonFacing = pistonState.get(FacingBlock.FACING);
		BlockPos offsetPos = pistonPos.offset(pistonFacing);
		BlockState offsetBlockState = world.getBlockState(offsetPos);
		if (BlockUtils.isUnbreakable(offsetBlockState.getBlock())) {
			return carving(world, pistonPos, offsetBlockState);
		}
		return true;
	}

	private boolean carving(World world, BlockPos pistonPos, BlockState unbreakableState) {
		PlayerEntity player = ((IPistonCache)world).getPistonCache(pistonPos);
		if (player != null) {
			LOGGER.debug("player carving!");
			return ServerPistonCarvingEvents.PLAYER.invoker().playerCarving(world, pistonPos, unbreakableState, player);
		} else {
			LOGGER.debug("machine carving!");
			return ServerPistonCarvingEvents.MACHINE.invoker().machineCarving(world, pistonPos, unbreakableState);
		}
	}
}
